unit StringUtils;

interface

type
 PCharSet = ^TCharSet;
 TCharSet = set of Char;

const
 DefaultDelimiters: TCharSet = [' ', #9, #13, #10];
 DefaultParamDelimiters: TCharSet = ['?', '&', '='];

function ExtractWord(const N: Word; const S: String; const WordDelims: TCharSet): String; {*}
function WordCount(const S: String; const WordDelims: TCharSet): Word; {*}
function QuotedWordCount(const S: String; const WordDelims: TCharSet): Word;
function ExtractQuotedWord(const N: Word; const S: String; const WordDelims: TCharSet): String;
procedure ReplaceEx(var S: String; A: String; const B: String);
//
function WordInString(const AWord, AString: String; Delimiters: TCharSet = [' ']): Integer;

implementation

uses
 StrUtils;

function ExtractWord(const N: Word; const S: String; const WordDelims: TCharSet): String;
 var
  I: Word;
  Count, Len: Word;
 begin
  Count:=0;
  I:=1;
  Len:=0;
  Result:='';

  while (I <= Length(S)) and (Count <> N) do
   begin
    while (I <= Length(S)) and (S[I] in WordDelims) do
     Inc(I);

     if I <= Length(S) then
      Inc(Count);

     while (I <= Length(S)) and not (S[I] in WordDelims) do
      begin
       if Count = N then
        begin
         Inc(Len);

         SetLength(Result, Len);
         Result[Len]:=S[I];
        end;

       Inc(I);
      end;
   end;
 end;

function WordCount(const S: String; const WordDelims: TCharSet): Word;
 var
  Count, I: Word;
 begin
  Count:=0;
  I:=1;

  while I <= Length(S) do
   begin
    while (I <= Length(S)) and (S[I] in WordDelims) do
     Inc(I);

    if I <= Length(S) then
     Inc(Count);

    while (I <= Length(S)) and not (S[I] in WordDelims) do
     Inc(I);
   end;

  Result:=Count;
 end;

function QuotedWordCount(const S: String; const WordDelims: TCharSet): Word;
 var
  Count, I: Word;
  Delims: TCharSet;
  Quoted: Boolean;
 begin
  Count:=0;
  I:=1;
  Delims:=WordDelims;
  Exclude(Delims, '"');
  Quoted:=false;

  while I <= Length(S) do
   begin
    while (I <= Length(S)) and (S[I] in Delims) do
     Inc(I);

    if I <= Length(S) then
     begin
      Inc(Count);
      if S[I]='"' then
       begin
        Quoted:=true;
        while (I<=Length(S)) and (S[I]='"') do
          Inc(I);
       end;
     end;

    if Quoted then
     begin
      while (I <= Length(S)) and not (S[I]='"') do
        Inc(I);
      Quoted:=false;
      while (I<=Length(S)) and (S[I]='"') do
        Inc(I);
     end
    else
     begin
      while (I <= Length(S)) and not (S[I] in Delims) do
       Inc(I);
     end;
   end;

  Result:=Count;
 end;

function ExtractQuotedWord(const N: Word; const S: String; const WordDelims: TCharSet): String;
 var
  I: Word;
  Count, Len: Word;
  Delims: TCharSet;
  Quoted: Boolean;
 begin
  Count:=0;
  I:=1;
  Len:=0;
  Result:='';
  Delims:=WordDelims;
  Exclude(Delims, '"');
  Quoted:=false;

  while (I <= Length(S)) and (Count <> N) do
   begin
    while (I <= Length(S)) and (S[I] in Delims) do
     Inc(I);

     if I <= Length(S) then
      begin
       Inc(Count);
       if S[I]='"' then
        begin
         Quoted:=true;
         while (I<=Length(S)) and (S[I]='"') do
           Inc(I);
        end;
      end;

    if Quoted then
     begin
      while (I <= Length(S)) and not (S[I]='"') do
       begin
        if Count = N then
         begin
          Inc(Len);

          SetLength(Result, Len);
          Result[Len]:=S[I];
         end;
        Inc(I);
       end;
      Quoted:=false;
      while (I<=Length(S)) and (S[I]='"') do
        Inc(I);
     end
    else
     begin
      while (I <= Length(S)) and not (S[I] in Delims) do
       begin
        if Count = N then
         begin
          Inc(Len);

          SetLength(Result, Len);
          Result[Len]:=S[I];
         end;

        Inc(I);
       end;
     end;
   end;
 end;

procedure ReplaceEx(var S: String; A: String; const B: String);
 var
  K{, L}: Word;
 begin
  K:=Pos(A, S);
  while K <> 0 do
   begin
    Delete(S, K, Length(A));
    Insert(B, S, K);
    {
    L:=K + Length(B);
    K:=Pos(A, Copy(S, L, Length(S)));
    if K <> 0 then
     begin
      Dec(K);
      Inc(K, L);
     end;
    }
    K:=PosEx(A, S, K+Length(B)-1);
   end;
 end;

function WordInString(const AWord, AString: String; Delimiters: TCharSet = [' ']): Integer;
 var
  i, k, l: Integer;
  b: Boolean;
begin
 {
 i:=Pos(AWord, AString);
 if i>0 then
  begin
   //word is found
   if i>1 then
     b:=AString[i-1] in Delimiters //symbol previous to word must be a delimiter
   else
     b:=true; //word is in the begin of string
   k:=i+Length(AWord);
   if k<=Length(AString) then //if word does not take whole string or not in the end of string...
     b:=b and (AString[k] in Delimiters); //...it must be followed by delimiter
   //
   if b then
     Result:=i
   else
     Result:=0;
  end
 else
   Result:=0; //word is not found at all
 }
 Result:=0;
 if (AWord='') or (AString='') then
   Exit;
 l:=Length(AString);
 k:=1;
 while Result=0 do
  begin
   i:=PosEx(AWord, AString, k);
   if i>0 then
    begin
     //word is found probably
     if i>1 then
       b:=AString[i-1] in Delimiters //symbol previous to word must be a delimiter
     else
       b:=true; //word is in the begin of string
     k:=i+Length(AWord);
     if k<=l then //if word does not take whole string or not in the end of string...
       b:=b and (AString[k] in Delimiters); //...it must be followed by delimiter
     //
     if b then
       Result:=i //word is found
     else
      begin
       if k>l then //end of string
         Break;
      end;
    end
   else
     Break; //word is not found at all
  end;
end;

end.
